home *** CD-ROM | disk | FTP | other *** search
- #include <stdlib.h>
- #include "gbuf.h"
- #include "move.h"
- #include "imagebuf.h"
-
- #include <string.h>
-
- int s_max_color(int bitpx, int nplanes) // Return max color in image
- {
- int src_max_color;
- switch(bitpx)
- {
- case 8: src_max_color = 255; break;
- case 2: src_max_color = 3; break;
- case 1:
- src_max_color = (nplanes == 1) ? 1 : 15; break;
- }
- return src_max_color;
- }
- /////////////////////////////
- int get_color_mult(int src_max_color, int dest_max_color) // color scaling
- { // if modes are
- if(dest_max_color >= src_max_color) // incompatible
- return dest_max_color / src_max_color;
- return src_max_color / dest_max_color;
- }
- ///////////////////////////
- inline int bw_pix(int color, int x, int y) // Transform color pix
- { // to B/W using pattern
- int sx = x % 8; // We suppose that 1st
- int sy = y % 8; // 16 patterns approxi-
- return (pattern[color][sy]) & (1 << sx) ? 1 : 0; // mates 16 colors
- }
- ////////////////////////
- int image_size(int width, int height, int bitpx, int nplanes) // BGI imagesize
- { // works incor-
- return ((width * bitpx + 7) >> 3) * nplanes * height; // rect
- }
- ////////////////////////
- GrafBuffer::GrafBuffer(loc dim, char* swapName, rect sa, int bpx, int np)
- {
- loaded = 0; // Buffer is not cleared
- buf_dim = dim; // Buffer dimentions, pixels
- file_name = strdup(swapName); // Swap file
-
- loc disp(bpx, np); // Display bpx and nplanes
- bitpx = disp.X; // Bit per pixel
- nplanes = disp.Y; // Number of planes
-
- bound_size.X = buf_dim.X; // Bound is swap area in memory
- bound_size.Y = BOUND_SIZE / image_size(dim.X, 1, bitpx, nplanes); // calculation of bound size
-
- FILE* Buf = fopen(file_name, "w+b"); // Buffer file, create it and
- fclose(Buf); // immediately close
-
- screen_area = sa; // Screen area (viewport)
- screen_position = rect(0, 0, sa.width() - 1, sa.height() - 1);
- image = NULL; // Keeps the bound
- }
- ///////////////////////
- void GrafBuffer::clear()
- {
- rewind(buffer);
- long len = imagesize();
- for(long i = 0; i < len; i++)
- fputc(255, buffer);
- loaded = 1; // Image allocated on disk
- }
- ///////////////////////
- int GrafBuffer::b_open() // Open swap file (created by constructor)
- {
- if(!(image = (imageP)malloc(BOUND_SIZE + sizeof(imageP))))
- return 0;
- buffer = fopen(file_name, "r+b");
- image->xmax = bound_size.X - 1;
- image->ymax = bound_size.Y - 1;
- return 1;
- }
- ///////////////////////
- void GrafBuffer::b_close() // Close swap file
- {
- fclose(buffer);
- delete image;
- image = NULL;
- }
- ///////////////////////
- long GrafBuffer::imagesize()
- {
- long size = image_size(buf_dim.X, 1, bitpx, nplanes) - sizeof(imageP);
- size *= buf_dim.Y;
- return size;
- }
- ///////////////////////
- void GrafBuffer::buffer_disk(rect src, char* name)
- {
- FILE* work;
- work = fopen(name, "w+b");
-
- int end_bound = src.corner.Y / bound_size.Y + 1; // lower bound
- int start_bound = src.origin.Y / bound_size.Y; // upper bound
-
- for(int i = start_bound; i < end_bound; i++) // for b. involved
- {
- get_bound(i); // Read bound from disk
-
- int s_y = (i > start_bound) ? 0 // y coord inside image
- : src.origin.Y - i * bound_size.Y;
- int e_y = (i < end_bound - 1) ? bound_size.Y - 1
- : src.corner.Y - i * bound_size.Y;
- int image_x = image->xmax; // We intend to cut
- int image_y = image->ymax; // image and need reserv
-
- cut_image(image, rect(0, 0, image->xmax, image->ymax),
- rect(src.origin.X, s_y, image->xmax, image->ymax));
- cut_image(image, rect(0, 0, image->xmax, image->ymax),
- rect(0, 0, src.corner.X - src.origin.X, e_y));
-
- fwrite(image->data, image_size(src.width(), e_y - s_y + 1,
- bitpx, nplanes), 1, work);
- image->xmax = image_x;
- image->ymax = image_y;
- }
- fclose(work);
- }
- //////////////////////
- void GrafBuffer::get_BW(int number)
- {
- int plane_size = (bound_size.X + 7) >> 3; // size of plane
- int scan_size = plane_size << 2; // size of scan line
- imageP work =
- (imageP)malloc(scan_size + sizeof(imageP)); // bitpx, nplanes));
- work->xmax = bound_size.X - 1; // We construct one-line
- work->ymax = 0; // "work" image; "image"
- image->ymax = (bound_size.Y - 1) << 2; // was color, "work" - BW
- int size = plane_size * bound_size.Y; // size of one (of 4) bounds
- int i, j, x; // image(COL)->work(BW)->image(BW)
- ImageBuffer im; // Buffer for 8 pixels of byte
- int vert_sh = bound_size.Y * number; // Offset in "buffer" file
- fseek(buffer, (long)(number) * size * 4, SEEK_SET);
- for(i = 0; i < 4; i++) // For 4 planes
- {
- for(j = 0; j < bound_size.Y; j++) // For all scan lines
- {
- fread(work->data, scan_size, 1, buffer);
- for(x = 0; x < plane_size; x++) // For plane
- {
- unsigned char pix = im.image_get_pixel(work, x,
- vert_sh + j);
- image->data[x + i * size + j * plane_size] = pix;
- }
- }
- }
- delete work;
- }
- //////////////////////
- imageP GrafBuffer::get_bound(int number) // get number-th bound, from 0
- {
- int size = image_size(bound_size.X, bound_size.Y, bitpx, nplanes);
- fseek(buffer, (long)number * size, SEEK_SET);
- fread(image->data, size, 1, buffer);
- return image;
- }
- //////////////////////
- void GrafBuffer::put_bound(int number)
- {
- int size = image_size(bound_size.X, bound_size.Y, bitpx, nplanes);
- fseek(buffer, (long)number * size, SEEK_SET);
- fwrite(image->data, size, 1, buffer);
- }
- //////////////////////
- void GrafBuffer::bound_screen(int number, loc comp_s, loc comp_d)
- {
- if(bound_size.Y * (number + 1) < screen_position.origin.Y // If this bound
- || bound_size.Y * number >= screen_position.corner.Y) // is invisible
- return;
- image = get_bound(number); // Read this bound
-
- int y1 = (screen_position.origin.Y > number * bound_size.Y) // screen
- ? screen_area.origin.Y
- : screen_area.origin.Y
- + (long)(number * bound_size.Y
- - screen_position.origin.Y) * comp_d.Y / comp_s.Y;
-
- int y3 = (screen_position.origin.Y > number * bound_size.Y)
- ? screen_position.origin.Y - number * bound_size.Y - 1 : 0;
-
- int y4 = (screen_position.corner.Y < (number + 1) * bound_size.Y)
- ? screen_position.corner.Y - number * bound_size.Y // image
- : bound_size.Y;
-
- image_screen(image, rect(screen_position.origin.X, y3,
- screen_position.corner.X, y4),
- loc(screen_area.origin.X, y1),
- bitpx, nplanes,
- comp_s, comp_d);
- }
- //////////////////////
- void GrafBuffer::screen_bound(int number)
- {
- if(bound_size.Y * (number + 1) < screen_position.origin.Y
- || bound_size.Y * number > screen_position.corner.Y)
- return;
-
- image = get_bound(number);
-
- int y1 = (screen_position.origin.Y > number * bound_size.Y)
- ? screen_area.origin.Y
- : screen_area.origin.Y + number * bound_size.Y
- - screen_position.origin.Y;
- int y2 = (screen_position.corner.Y < (number + 1) * bound_size.Y)
- ? screen_area.corner.Y - 1
- : screen_area.origin.Y + (number + 1) * bound_size.Y
- - screen_position.origin.Y - 1;
-
- int y3 = (screen_position.origin.Y > number * bound_size.Y)
- ? screen_position.origin.Y - number * bound_size.Y - 1 : 0;
-
- screen_image(image, rect(screen_area.origin.X, y1,
- screen_area.corner.X, y2),
- loc(screen_position.origin.X, y3));
- put_bound(number);
- }
- //////////////////////
- void GrafBuffer::buffer_screen(loc comp_s, loc comp_d)
- {
- int bound_num = buf_dim.Y / bound_size.Y + 1;
- for(int i = 0; i < bound_num; i++)
- bound_screen(i, comp_s, comp_d);
- }
- //////////////////////
- void GrafBuffer::buffer_screen(rect temp, // temp - on screen
- loc comp_s, loc comp_d)
- {
- int start_bound = ((long)(temp.origin.Y - screen_area.origin.Y)
- * comp_s.Y / comp_d.Y + screen_position.origin.Y)
- / bound_size.Y;
- int end_bound = ((long)(temp.corner.Y - screen_area.origin.Y)
- * comp_s.Y / comp_d.Y + screen_position.origin.Y)
- / bound_size.Y + 1;
-
- for(int i = start_bound; i < end_bound; i++)
- {
- image = get_bound(i);
-
- int y1 = ((long)(temp.origin.Y
- - screen_area.origin.Y) * comp_s.Y / comp_d.Y
- + screen_position.origin.Y
- > i * bound_size.Y) // screen
- ? temp.origin.Y
- : screen_area.origin.Y
- + (long)(i * bound_size.Y
- - screen_position.origin.Y) * comp_d.Y / comp_s.Y;
-
- int y3 = ((long)(temp.origin.Y - screen_area.origin.Y)
- * comp_s.Y / comp_d.Y + screen_position.origin.Y
- > i * bound_size.Y)
- ? screen_position.origin.Y - i * bound_size.Y
- + (long)(temp.origin.Y - screen_area.origin.Y)
- * comp_s.Y / comp_d.Y
- : 0;
-
- int y4 = (screen_position.origin.Y + (temp.corner.Y
- - screen_area.origin.Y) * comp_s.Y / comp_d.Y
- < (i + 1) * bound_size.Y)
- ? screen_position.origin.Y + (long)(temp.corner.Y
- - screen_area.origin.Y) * comp_s.Y / comp_d.Y
- - i * bound_size.Y // image
- : bound_size.Y;
-
- image_screen(image,
- rect(screen_position.origin.X + (long)(temp.origin.X
- - screen_area.origin.X) * comp_s.X / comp_d.X, y3,
- screen_position.origin.X + (long)(temp.corner.X
- - screen_area.origin.X) * comp_s.X / comp_d.X, y4),
- loc(temp.origin.X, y1),
- bitpx, nplanes,
- comp_s, comp_d, 1);
-
- }
- }
- //////////////////////
- void GrafBuffer::screen_buffer()
- {
- int bound_num = buf_dim.Y / bound_size.Y + 1;
- for(int i = 0; i < bound_num; i++)
- screen_bound(i);
- }
- //////////////////////
- void GrafBuffer::scroll(int shift, int direction, int show)
- {
- rect reserv = screen_area;
- rect res = screen_position;
-
- switch(direction)
- {
- case UP:
- if(screen_position.corner.Y + shift > buf_dim.Y)
- return;
-
- screen_position.origin.Y += shift;
- screen_position.corner.Y += shift;
- if(show)
- buffer_screen();
- return;
- case DN:
- if(screen_position.origin.Y - shift < 0)
- return;
- screen_position.origin.Y -= shift;
- screen_position.corner.Y -= shift;
- if(show)
- buffer_screen();
- return;
- case LEFT:
- if(screen_position.corner.X + shift > buf_dim.X)
- return;
- screen_position.origin.X += shift;
- screen_position.corner.X += shift;
- if(show)
- buffer_screen();
- return;
- case RIGHT:
- if(screen_position.origin.X - shift < 0)
- return;
- screen_position.origin.X -= shift;
- screen_position.corner.X -= shift;
- buffer_screen();
- return;
-
- }
- }
- /////////////////////////////
- int pcx_file_buffer(GrafBuffer* buf, loc pos, char* name, int col)
- {
- FILE* f;
- if((f = fopen(name, "rb")) == NULL)
- return 0; // Open PCX file
- pcxheader p; // Read PCX header
- if(!get_pcx_header(f, &p)) // Simple error handler
- {
- fclose(f);
- return 0;
- }
-
- if(p.bitpx == 1 && p.nplanes == 1) // Trouble: after call to
- { // the pcx_bw_to_col() 8 bit
- fclose(f); // rounded image will (possib-
- pcx_bw_to_col(name, "tmp____u.pcz"); // ly) replace 16 bit one. To
- delete name; // read new pcx header we need
- name = strdup("tmp____u.pcz"); // additional call to header
-
- if((f = fopen(name, "rb")) == NULL) // reader function
- return 0;
- get_pcx_header(f, &p);
- }
-
- int bplin; // bytes per line in same buffer if compatible, or in new buffer
-
- int xsize = p.x2 - p.x1 + 1;
- int ysize = p.y2 - p.y1 + 1;
-
- if(pos.X + xsize >= buf->buf_dim.X // If picture is larger
- || pos.Y + ysize >= buf->buf_dim.Y) // than buffer - resize
- { // all data will be lost
- buf->b_close();
- buf->bound_size.X = buf->buf_dim.X = pos.X + xsize + 1;
- buf->bound_size.Y =
- (BOUND_SIZE / (::imagesize(0, 0, buf->bound_size.X - 1, 0)
- - sizeof(imageP) - 2));
- if(buf->bound_size.Y > buf->buf_dim.Y)
- buf->bound_size.Y = buf->buf_dim.Y;
-
- buf->buf_dim.Y = pos.Y + p.y2 - p.y1 + 1;
- buf->b_open();
- }
-
- pcxheader work;
- GrafBuffer* work_gb;
-
- int start_bound;
- int end_bound;
- int x;
- int y;
- int start_x;
- int plane_num = p.nplanes - 1; // number of current plane, cycle variable
-
- if(p.nplanes != buf->nplanes || p.bitpx != buf->bitpx // if formates are
- || col != 16)
- { // incompatible
- work_gb = // Create new buffer
- new GrafBuffer(loc((p.x2 - p.x1 + 1 + 7) / 8 * 8,
- p.y2 - p.y1 + 1),
- "__work.buf", rect(0, 0, 10, 20), p.bitpx, p.nplanes);
- if(!(work_gb->b_open())) // Not enough memory to open 2-th
- { // buffer
- delete work_gb;
- fclose(f);
- return 0;
- }
- bplin = p.bplin; /* Bytes per line */
- work_gb->clear();
- start_bound = 0;
- end_bound = (p.y2 - p.y1 + 1) / work_gb->bound_size.Y + 1;
- x = plane_num * bplin; // start x byte in source rectangle
- y = start_x = 0;
- }
- else // formates are compatible
- { // Now we can call it for compatible and incompatible
- work_gb = buf; // formates
- put_pcx_header(NULL, &work, // tric to obtain bplin
- loc(buf->bound_size.X, buf->bound_size.Y)); // for "bound" image
- bplin = work.bplin;
- start_bound = pos.Y / work_gb->bound_size.Y; // In "old" buffer
- end_bound = (pos.Y + p.y2 - p.y1 + 1) / work_gb->bound_size.Y + 1;
- x = pos.X * work_gb->bitpx / 8 + plane_num * bplin; // start x byte in source rectangle
- y = pos.Y - work_gb->bound_size.Y * start_bound; // start y in current bound
- start_x = (pos.X * work_gb->bitpx + 7) / 8; // start x byte in image
- }
-
- int w_data = work_gb->nplanes * bplin; // length of image line, bytes
- int i = start_bound;
-
- work_gb->get_bound(i);
- int ex = 0;
- buf->loaded = 1;
- while(!ex)
- {
- int count = 1; // PCX counter
- unsigned char ch = fgetc(f); // read char
- if((ch & 0xC0 ) == 0xC0) // if two upper bits == 1
- {
- count = 63 & ch; // use 6 low bits as counter
- ch = fgetc(f); // read the pattern
- }
- for(int j = 0; j < count; j++)
- {
- unsigned char ch1;
- ch1 = work_gb->image->data[x + w_data * y];
- work_gb->image->data[x + w_data * y] = ch;
- x++;
- if(x == bplin * plane_num + start_x + p.bplin)
- {
- work_gb->image->data[x + w_data * y - 1] =
- (ch & (255 << xsize % 8))
- | ((255 >> (8 - xsize % 8) & ch1));
-
- // If end of scan line or end of plane
- if(plane_num == 0) // If end of scan line
- {
- plane_num = work_gb->nplanes - 1;
- x = start_x + plane_num * bplin;
-
- if(y + 1 < work_gb->bound_size.Y
- /* ! */ && i * work_gb->bound_size.Y + y + 1 < pos.Y + ysize)
- y++;
- else
- {
- work_gb->put_bound(i);
- i++;
- if(i < end_bound)
- {
- work_gb->get_bound(i);
- y = 0;
- }
- else // Exit loop
- {
- fclose(f);
- ex = 1;
- break;
- }
- }
- }
- else // End of plane
- {
- plane_num--;
- x = plane_num * bplin + start_x;
- }
- }
- }
- }
-
- if(p.nplanes != buf->nplanes || p.bitpx != buf->bitpx // if formates are
- || col != 16)
- { // incompatible
- int src_max_color = s_max_color(p.bitpx, p.nplanes); // max color in src
- int dest_max_color = getmaxcolor();
- int color_mult = get_color_mult(src_max_color, dest_max_color); // Simple color filter
- int color_mult_15 = get_color_mult(src_max_color, 15);
- int work_y = 0; // in "new" buffer
- int bound1 = pos.Y / buf->bound_size.Y;
- int bound2 = 0;
- int y = pos.Y - bound1 * buf->bound_size.Y; // Inside (buf) image
- work_gb->get_bound(0); // Read src and det bounds
- buf->get_bound(bound1);
- while(1)
- {
- if(work_y == work_gb->bound_size.Y) // End of (work) bound
- {
- work_y = 0; // Prepare to load new (work)
- bound2++; // bound
- if(bound2 == (p.y2 - p.y1 + 1) / work_gb->bound_size.Y + 1)
- { // Last bound to read
- buf->put_bound(bound1); // flash the rest and exit
- break;
- }
- work_gb->get_bound(bound2); // Else - load next bound
- }
- if(y == buf->bound_size.Y) // End of (buf) bound
- {
- buf->put_bound(bound1); // Swap modified bound
- y = 0; // and prepare to load next
- bound1++;
- buf->get_bound(bound1); // Load next (buf) bound
- }
-
- int end_y = (bound1 == (pos.Y + p.y2 - p.y1 + 1)
- / buf->bound_size.Y)
- ? pos.Y + p.y2 - p.y1 + 1 - bound1 * buf->bound_size.Y
- : buf->bound_size.Y;
-
- for(; y < end_y && work_y < work_gb->bound_size.Y;
- y++, work_y++)
- {
- for(int x = pos.X; x < pos.X + p.x2 - p.x1 + 1; x++)
- {
- int pix = image_get_pixel(work_gb->image,
- loc(x - pos.X, work_y), p.bitpx, p.nplanes);
- if(dest_max_color < src_max_color)
- {
- if(src_max_color <= 15)
- pix = (bw_pix(pix * color_mult_15, x,
- y + bound1 * buf->bound_size.Y))
- ? pix / color_mult
- : dest_max_color - pix / color_mult;
- else
- pix = (bw_pix(pix / color_mult_15, x,
- y + bound1 * buf->bound_size.Y))
- ? pix / color_mult
- : dest_max_color - pix / color_mult;
- }
- else
- if(dest_max_color > src_max_color)
- pix = pix * color_mult;
-
- if(pix != col)
- image_put_pixel(buf->image, loc(x, y), pix,
- buf->bitpx, buf->nplanes);
- }
- }
- if(bound1 == (pos.Y + p.y2 - p.y1 + 1) / buf->bound_size.Y)
- {
- buf->put_bound(bound1);
- break;
- }
- }
- work_gb->b_close();
- delete work_gb;
- }
- return 1;
- }
- ///////////////////////////
- inline void pcx_put_char(uchar count, uchar ch, FILE* f)
- {
- if(count > 1 || (0xC0 == (0xC0 & ch)))
- fputc(count | 128 | 64, f); // Write counter
- fputc(ch, f); // Write pattern
- }
- //////////////////////////
- void GrafBuffer::pcx_buffer_file(rect src, char* name)
- {
- if(src.right() >= bound_size.X) // If any mistake
- return;
-
- FILE* f = fopen(name, "w+b"); // Open target file
- pcxheader p; // Put header
- put_pcx_header(f, &p, loc(src.width(), src.height())); // of target file
-
- pcxheader work; // The pseudo-header
- work.bitpx = 1; // contains information
- work.nplanes = 4; // about current
- work.x1 = 0; // graphics buffer
- work.y1 = 0;
- work.x2 = bound_size.X - 1;
- work.y2 = bound_size.Y - 1;
- work.bplin = (bound_size.X + 7) >> 3;
-
- int start_bound = src.origin.Y / bound_size.Y; // Start buffer bound
- int end_bound = src.corner.Y / bound_size.Y + 1;
- int plane_num = 3; // Number of current plane,
- // work.nplanes - 1 == 3 for VGA/EGA
- int w_data = work.nplanes * work.bplin; // Length of image line, bytes
- uchar count = 1; // PCX counter
-
- int start_x = src.origin.X / 8; // Between beginning of plane and
- // beginning of rect, bytes
- int src_bytes = src.width() / 8; // Significant bytes in src scan line
- int x = start_x + plane_num * work.bplin; // Start x in current plane of
- // source rectangle
- int i = start_bound; // Counter of biunds
- int y = src.origin.Y - bound_size.Y * i; // Start y in current bound
-
- get_bound(i); // Read bound
- unsigned char ch = image->data[x + w_data * y]; // Get start char
- int plane_end = x + src_bytes; // End of current plane
-
- while(1) // The main cycle
- {
- x++; // Move the pointer in image
- if(x == plane_end)
- { // End of scan line or end of plane.
- if(plane_num != 0) // If it is end of plane,
- { // not of scan line.
- plane_num--; // 3-2-1-0 in BGI == 0-1-2-3 in PCX
- x = plane_num * work.bplin + start_x; // Start x in
- plane_end -= work.bplin; // new plane.
- }
- else // It is end of scan line
- {
- if(i < end_bound) // Not last bound.
- {
- plane_num = 3; // work.nplanes - 1;
- x = start_x + 3 * work.bplin; // Start x in 4th plane
- plane_end = x + src_bytes; // End of 4th plane
- if(y + 1 == bound_size.Y) // If bottom of bound
- {
- i++; // Go to next bound
- y = 0;
- get_bound(i); // Read new bound
- }
- else
- y++; // Continue with this bound
- /* The following code, marked !! is absolutely unnecessary and ineffective.
- But Painbrush use stop-on-the-scan-line technology. I don't know why.
- This code is compatible with Paintbrush.
- */
- pcx_put_char(count, ch, f); // !!
- count = 0; // !!
- ch = image->data[x + w_data * y]; // !!
-
- }
- else // Last bound
- {
- pcx_put_char(count, ch, f); // Write counter last time
- break; // exit the loop
- }
- }
- }
-
- if(ch == image->data[x + w_data * y]) // If current data is the same
- { // as previous, keeped in ch
- if(count == 63)
- {
- pcx_put_char(count, ch, f);
- count = 1;
- }
- else
- count++;
- }
- else // New data value
- {
- pcx_put_char(count, ch, f); // Flash old counter
- count = 1; // Start new counter
- ch = image->data[x + w_data * y]; // Read next
- }
- }
- fclose(f);
- }
- /////////////////////////
- /*
- void main()
- {
- int gdriver = DETECT, gmode;
- initgraph(&gdriver, &gmode, "");
-
- GrafBuffer* g = new GrafBuffer(loc(1001, 1000), "work.buf",
- rect(0, 0, 600, 400));
- g->b_open();
- g->clear();
-
- char* name = strdup("c:\\myprog\\sova.pcx");
- pcx_file_buffer(g, loc(0, 0), name);//, LIGHTGRAY);
- g->buffer_screen();
-
- g->pcx_buffer_file(rect(64, 40, 191, 300), "work.pcx");
-
- pcx_file_buffer(g, loc(0, 0), "work.pcx");
- g->buffer_screen();
-
- g->b_close();
- delete g;
- delete name;
-
- closegraph();
- }
- */
-
-